package edu.washington.cs.sounddetector.server.api.methodlogic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Transaction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.washington.cs.sounddetector.server.api.method.GetOldNotifications;
import edu.washington.cs.sounddetector.server.api.method.GetSound;
import edu.washington.cs.sounddetector.server.api.method.GetSounds;
import edu.washington.cs.sounddetector.server.api.methodresult.GetOldNotificationsResult;
import edu.washington.cs.sounddetector.server.api.methodresult.GetSoundResult;
import edu.washington.cs.sounddetector.server.api.methodresult.GetSoundsResult;
import edu.washington.cs.sounddetector.server.api.object.Notification;
import edu.washington.cs.sounddetector.server.api.object.SoundClass;
import edu.washington.cs.sounddetector.server.database.Notifications;
import edu.washington.cs.sounddetector.server.database.ReceiverPhone;
import edu.washington.cs.sounddetector.server.database.Sound;

/**
 * ReadLogic implements logic that performs read-only operations on the database.
 * 
 * @author the.dylan.price@gmail.com
 * 
 */
public class ReadLogic
{
    private static final Log log = LogFactory.getLog(WriteLogic.class);

    private PersistenceManagerFactory pmf;

    public ReadLogic(PersistenceManagerFactory pmf)
    {
        this.pmf = pmf;
    }

    public GetOldNotificationsResult getOldNotifications(GetOldNotifications method)
    {
        PersistenceManager pm = pmf.getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try
        {
            tx.begin();
            // TODO: change when we implement users
            ReceiverPhone receiverPhone = ReceiverPhone.query(pm, "1", method.getPhoneId());
            if (receiverPhone == null)
                return GetOldNotificationsResult.failurePhoneDoesNotExist(method.getPhoneId());
            // TODO: change when we implement users
            Collection<Notifications> oldNotifications = Notifications.query(pm, "1",
                    receiverPhone, true, method.getGreaterThanDate(), method.getLessThanDate());
            List<Notification> notifications = new ArrayList<Notification>();
            for (Notifications on : oldNotifications)
            {
                SoundClass soundClass = new SoundClass(on.getSoundClass().getSoundClass(), on
                        .getSoundClass().getRgbColor());
                Notification notification = new Notification(soundClass, on.getSoundClass()
                        .getDetectorId(), on.getPeakEvents());
                notifications.add(notification);
            }
            tx.commit();
            return GetOldNotificationsResult.success(notifications);
        }
        finally
        {
            if (tx.isActive())
                tx.rollback();
            pm.close();
        }
    }

    public GetSoundsResult getSounds(GetSounds method)
    {
        PersistenceManager pm = pmf.getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try
        {
            tx.begin();
            // TODO: change when we implement users
            Collection<Sound> dbSounds = Sound.query(pm, "1", method.getDetectorId());
            if (dbSounds.isEmpty())
                return GetSoundsResult.failureDetectorIdDoesNotExist(method.getDetectorId());

            Map<SoundClass, List<Long>> sounds = new HashMap<SoundClass, List<Long>>();
            for (Sound sound : dbSounds)
            {
                SoundClass soundClass = new SoundClass(sound.getSoundClass().getSoundClass(), sound
                        .getSoundClass().getRgbColor());

                Long id = sound.getId();
                if (sounds.get(soundClass) == null)
                {
                    sounds.put(soundClass, new ArrayList<Long>());
                }
                sounds.get(soundClass).add(id);
            }
            tx.commit();
            return GetSoundsResult.success(sounds);
        }
        finally
        {
            if (tx.isActive())
                tx.rollback();
            pm.close();
        }
    }

    public GetSoundResult getSound(GetSound method)
    {
        PersistenceManager pm = pmf.getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try
        {
            tx.begin();
            Sound sound = pm.getObjectById(Sound.class, method.getSoundId());
            tx.commit();
            return GetSoundResult.success(sound.getSound());
        }
        catch (JDOObjectNotFoundException e)
        {
            return GetSoundResult.failureSoundDoesNotExist(method.getSoundId());
        }
        finally
        {
            if (tx.isActive())
                tx.rollback();
            pm.close();
        }
    }

}
